package com.driving.single.frontend.user.service.impl;

import com.driving.single.common.domain.TbUser;
import com.driving.single.common.entity.DrivingResult;
import com.driving.single.common.entity.LoginResult;
import com.driving.single.common.entity.SmsResult;
import com.driving.single.common.exception.DrivingException;
import com.driving.single.common.mapper.TbUserMapper;
import com.driving.single.common.redis.service.CommonRedisSendSmsService;
import com.driving.single.common.redis.service.CommonRedisUserService;
import com.driving.single.common.sms.service.SendSmsService;
import com.driving.single.common.utils.IDUtils;
import com.driving.single.common.utils.JsonUtils;
import com.driving.single.common.utils.MD5Utils;
import com.driving.single.frontend.user.dto.param.PhoneRegisterParam;
import com.driving.single.frontend.user.service.FrontendUserService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 用户模块  业务层 实现类
 *
 * @author xsfno1
 * @version v1.0.0
 * @date 2020/2/20
 **/
@Service
public class FrontendUserServiceImpl implements FrontendUserService {
    @Resource
    private TbUserMapper tbUserMapper;
    @Resource
    private CommonRedisUserService commonRedisUserService;
    /**
     * SMS服务类
     */
    @Resource
    private SendSmsService sendSmsService;
    /**
     * SMS-Redis服务类
     */
    @Resource
    private CommonRedisSendSmsService commonRedisSendSmsService;

    /**
     * 用户登录接口
     *
     * @param account  帐号
     * @param password 密码
     */
    @Override
    public DrivingResult userLogin(String account, String password) {
        // 1.将前端的密码进行加密处理
        String md5Pwd = MD5Utils.digest(password);
        // 2.与数据库比对
        Example example = new Example(TbUser.class);
        example.createCriteria().andEqualTo("phone", account);
        List<TbUser> users = this.tbUserMapper.selectByExample(example);
        // 3.结果
        if (users != null && users.size() == 1) {
            // 4.登录成功：保存用户登录状态
            if (users.get(0).getPassword().equals(md5Pwd)) {
                // 4.x 用户登录成功逻辑执行封装
                return this.loginSuccessResult(users.get(0));
            }
            throw new DrivingException("帐号或密码错误！");
        }
        throw new DrivingException("用户不存在！");
    }

    /**
     * 用户登录 手机验证码发送 接口
     *
     * @param phone 用户登录手机号码
     */
    @Override
    public DrivingResult sendLoginSms(String phone) {
        // 1.手机号码校验
        // 2.查询数据库，根据手机号判断用户是否存在
        Integer count = this.checkPhoneOrUsernameRepeat(phone, null);
        if (count == 0) {
            throw new DrivingException("手机号尚未注册，请先前往注册！");
        }
        // 3.发送SMS
        String loginSms = null;
        try {
            loginSms = this.sendSmsService.sendLoginSms(phone);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //  4.转换格式
        return loginSms == null ?
                DrivingResult.error("短信发送异常，请稍后重试！") :
                this.smsJsonToSmsResult(loginSms);
    }

    /**
     * 用户登录(手机验证码登录)接口
     *
     * @param phone 用户注册手机号码
     */
    @Override
    public DrivingResult userLoginWithPhoneCode(String phone, String code) {
        // 1.手机号码校验
        // 2.查询数据库 检查手机号是否存在
        int count = this.checkPhoneOrUsernameRepeat(phone, null);
        if (count == 0) {
            throw new DrivingException("手机号尚未注册，请先前往注册！");
        }
        // 3.校验手机验证码
        String redisCode = this.commonRedisSendSmsService.selectLoginCodeFromRedis(phone);
        if (redisCode == null) {
            throw new DrivingException("验证码已过期，请重新发送！");
        }
        if (!redisCode.equals(code)) {
            throw new DrivingException("验证码错误，请核实！");
        }
        // 4.验证成功，允许登录，执行登录逻辑，同时删除Redis验证码缓存
        Example example = new Example(TbUser.class);
        example.createCriteria().andEqualTo("phone", phone);
        List<TbUser> users = this.tbUserMapper.selectByExample(example);
        if (users != null && users.size() == 1) {
            TbUser tbUser = users.get(0);
            // 4.x 删除Redis登录验证码缓存(不需要强制同步)
            try {
                this.commonRedisSendSmsService.deleteLoginCodeFromRedis(phone);
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 4.x 用户登录成功逻辑执行封装
            return this.loginSuccessResult(tbUser);
        }
        throw new DrivingException("帐号出现异常，请与客服联系或稍后重试！");
    }

    /**
     * 用户登录成功逻辑执行封装
     */
    private DrivingResult loginSuccessResult(TbUser tbUser) {
        // 4.1生成随机ID作为Redis-token的KEY
        String token = UUID.randomUUID().toString();
        // 4.2封装登录用户模型
        LoginResult loginResult = new LoginResult();
        loginResult.setToken(token);
        loginResult.setUserid(tbUser.getId().toString());
        loginResult.setUsername(tbUser.getUsername());
        // 4.3添加到Redis
        Integer flag = this.commonRedisUserService.addUserLoginResultToRedis(loginResult);
        if (flag != 200) {
            // 4.4失败返回
            throw new DrivingException("登录发生异常！请稍后重试！");
        }
        // 4.4成功返回
        return DrivingResult.ok(loginResult);
    }

    /**
     * 用户注册验证码发送 接口
     *
     * @param phone 用户注册手机号码
     */
    @Override
    public DrivingResult sendRegisterSms(String phone) {
        // 1.手机号码校验
        // 2.查询数据库是否存在用户手机号
        Integer count = this.checkPhoneOrUsernameRepeat(phone, null);
        if (count > 0) {
            throw new DrivingException("手机号已被注册，请前往登录！");
        }
        // 3.发送SMS
        String registerSms = null;
        try {
            registerSms = this.sendSmsService.sendRegisterSms(phone);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (registerSms == null) {
            return DrivingResult.error("短信发送异常，请稍后重试！");
        }
        // 4.转换格式
        return this.smsJsonToSmsResult(registerSms);
    }

    /**
     * 用户注册（手机验证码注册） 接口
     *
     * @param phoneRegisterParam {@link PhoneRegisterParam} 用户[手机短信]注册参数类
     */
    @Override
    public DrivingResult userRegisterWithCode(PhoneRegisterParam phoneRegisterParam) {
        // 1.手机号码校验
        // 2.查询数据库 检查手机号是否重复
        int count = this.checkPhoneOrUsernameRepeat(phoneRegisterParam.getPhone(), null);
        if (count > 0) {
            throw new DrivingException("手机号已被注册，请前往登录！");
        }
        // 3.校验手机验证码
        String redisCode = this.commonRedisSendSmsService.selectRegisterCodeFromRedis(phoneRegisterParam.getPhone());
        if (redisCode == null) {
            throw new DrivingException("验证码已过期，请重新发送！");
        }
        if (!redisCode.equals(phoneRegisterParam.getCode())) {
            throw new DrivingException("验证码错误，请核实！");
        }
        // 4.插入数据库
        Date date = new Date();
        TbUser tbUser = new TbUser();
        Long id = IDUtils.genItemId();
        tbUser.setId(id);
        tbUser.setUsername("驾校用户ID" + id);
        tbUser.setPhone(phoneRegisterParam.getPhone());
        // 帐号状态,1:正常；2:封停；3:删除
        tbUser.setStatus(1);
        // 密码加密后存入
        tbUser.setPassword(MD5Utils.digest(phoneRegisterParam.getPassword()));
        tbUser.setCreated(date);
        tbUser.setUpdated(date);
        return this.tbUserMapper.insertSelective(tbUser) == 0 ?
                DrivingResult.error("注册失败，请稍后重试！") :
                DrivingResult.ok("注册成功，请前往登录！");
    }

    /**
     * 检查 手机号 是否重复 接口
     *
     * @param phone 手机号码
     */
    @Override
    public DrivingResult checkPhone(String phone) {
        int count = this.checkPhoneOrUsernameRepeat(phone, null);
        if (count > 0) {
            throw new DrivingException("手机号已存在！");
        }
        return DrivingResult.ok();
    }

    /**
     * 检查 用户名 是否重复 接口
     *
     * @param username 用户名
     */
    @Override
    public DrivingResult checkUsername(String username) {
        int count = this.checkPhoneOrUsernameRepeat(null, username);
        if (count > 0) {
            throw new DrivingException("用户名已存在！");
        }
        return DrivingResult.ok();
    }

    /**
     * 根据 用户ID 获取用户信息 接口
     *
     * @param uid 用户ID
     */
    @Override
    public DrivingResult selectTbUserById(Long uid) {
        TbUser tbUser = this.tbUserMapper.selectByPrimaryKey(uid);
        return DrivingResult.ok(tbUser);
    }

    /**
     * 查询数据库 检查手机号或用户名是否重复
     *
     * @param phone    手机号
     * @param username 用户名
     */
    private Integer checkPhoneOrUsernameRepeat(String phone, String username) {
        Example example = new Example(TbUser.class);
        Example.Criteria criteria = example.createCriteria();
        if (!StringUtils.isEmpty(phone)) {
            criteria.andEqualTo("phone", phone);
        }
        if (!StringUtils.isEmpty(username)) {
            criteria.andEqualTo("username", username);
        }
        return this.tbUserMapper.selectCountByExample(example);
    }

    /**
     * 格式转换 JSON->POJO ：SMS --》 SmsResult
     */
    private DrivingResult smsJsonToSmsResult(String smsJson) {
        try {
            SmsResult smsResult = JsonUtils.jsonToPojo(smsJson, SmsResult.class);
            if (smsResult != null) {
                if (smsResult.getMessage().equals("OK")) {
                    return DrivingResult.ok();
                }
                return DrivingResult.error(smsResult.getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return DrivingResult.error(e.toString());
        }
        return DrivingResult.error("短信发送异常，请稍后重试！");
    }
}
